package com.basker.pisces.springcloud.feign;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import org.springframework.util.Assert;

import com.basker.pisces.utils.ReflectionUtils;

public class FeignClientFactoryBeanAccessor {

    private static volatile boolean FIELDS_INITIALED = false;
    private static final Map<String, Field> fields = new HashMap<>();

    public static Object getFieldValue(Object feignClientFactoryBean, String name) {
        assertBeanNotNull(feignClientFactoryBean);

        if (!FIELDS_INITIALED) {
            initialFields(feignClientFactoryBean.getClass());
        }

        Field field = fields.get(name);
        assertField(name, field);

        return ReflectionUtils.getFieldValue(field, feignClientFactoryBean);
    }

    public static void setFieldValue(Object feignClientFactoryBean, String name, Object value) {
        assertBeanNotNull(feignClientFactoryBean);

        if (!FIELDS_INITIALED) {
            initialFields(feignClientFactoryBean.getClass());
        }

        Field field = fields.get(name);
        assertField(name, field);

        ReflectionUtils.setFieldValue(field, feignClientFactoryBean, value);
    }

    private static void assertBeanNotNull(Object feignClientFactoryBean) {
        Assert.notNull(feignClientFactoryBean, "parameter 'feignClientFactoryBean' is required");
    }

    private static void assertField(String name, Field field) {
        if (field == null) {
            throw new IllegalArgumentException(name + " is not found in FeignClientFactoryBean!");
        }
    }

    private synchronized static void initialFields(Class<? extends Object> beanClass) {
        Field[] declaredFields = beanClass.getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            fields.put(field.getName(), field);
        }

        FIELDS_INITIALED = true;
    }

}
